// Copyright (C) 2010  Joan Puigcerver Perez, <joapuipe@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef __MOVIES_HPP__
#define __MOVIES_HPP__

//#include <map>
#include <unordered_map>
#include <list>
#include <vector>
#include <string>
#include <cstring>

#include <Movie.hpp>
#include <LogUtils.hpp>
#include <StringTrie.hpp>

/** File where movies info is stored. */
#define MOVIES_XML "xml/movies.xml"
/** XML Schema used to check the format of MOVIES_XML. */
#define MOVIES_XSD "xml/movies.xsd"

class Database;

/**
 * \class Movies
 *
 * This class is used to manage the set of movies in the database.
 * Each Movie node is created dinamically and its address is stored
 * in a vector of pointers. In addition, it is also created a new node
 * in a map. This map is used to find the association title-movie in O(log n).
 * People class has a similar behaviour.
 * \see People
 */
/*struct CComp {
  bool operator () (const char * l, const char * r) const
  { return strcmp(l,r) == 0; }
  };*/

class Movies {
private:
  std::ostream& logfile;
  ost::Mutex&  log_mutex;

  //typedef std::map<const std::string*,Movie*>::iterator mIter;
  //std::map<const std::string*, Movie*, CComp> movies;
  typedef std::unordered_map<const std::string&, Movie*> MHashMap;
  typedef MHashMap::iterator mIter;
  MHashMap movies;
  size_t num_movies;
  
  /**
   * Function used create and to add a new Movie into de database. 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */
  Movie* add_movie(const std::string& title, const Year year, 
		   const Media media, const bool suspended);
  /** 
   * Function used to add a new aka title to a given Movie (as a pointer). 
   * This function can't be used publicly. Use load() instead.
   * @see load
   */
  void add_aka(const char * aka, Movie* movie);
  
public:
  /** 
   * Constructor.
   *
   * @param logf Output stream used to print log messages.
   * @param logm Mutex to control the access to logf.
   */
  Movies(std::ostream& logf = std::cout, ost::Mutex& logm = LOGmutex); 

  /**
   * Destructor. Deletes all the created Movie objects.
   */
  ~Movies();

  /**
   * This method is used to load a movies XML file into a desired database.
   * It was not necessary to pass a Database pointer to load the movies set
   * because movies insertion does not interact with people data, only a 
   * pointer to a Movies class was necessary, but in order to uniform the 
   * interface of Movies and People functions it was preferred to pass the
   * Database pointer.
   * @see People::load
   */
  bool load(Database* database);

  /**
   * This method returns the pointer to a Movie object wich match
   * with the title given by parameters. If the title is just an aka title
   * (it is not the main title for any movie) for a single movie, then
   * this movie is returned.
   */
  Movie* search(const std::string& title);

  /** This returns the number of movies in the database. */
  size_t size(void) const;

  friend class SAXMoviesHandler;
  friend class Database;
};

#endif
